// import SVGCheck from '@mdi/svg/svg/check-bold.svg';
import SVGCheck from '../../svg/check.svg';
import SVGChevronRight from '../../svg/chevron-right.svg';
import type { PopupPosition, Pos } from '../popup/popup';
import { Selector } from '../selector/selector';
import { popMenuStyle } from './popMenu.css';

type RowType = Record<string | number, unknown>;

type ColumnOption = {
	/**
	 * if allow children then must both specify expand key and children key
	 */
	children?: number | string;
	/**
	 * if allow children then must both specify expand key and children key
	 */
	icon?: number | string;
	text?: number | string;
	disabled?: number | string;
	type?: number | string;
	checked?: number | string;
	onClick?: number | string;
};

export type PopMenuOptions = {
	columnOption?: ColumnOption;
	refer?: HTMLElement;
	useAction?: boolean;
	// maxShowLines?: number;
	focus?: boolean;
	popupPosition?: PopupPosition | Pos;
	noIndicator?: boolean;
	width?: number | string;
	minWidth?: number | string;
	maxWidth?: number | string;
	path?: RowType[];
	extra?: unknown;
};

export type MenuSelectCallback = (row: RowType, path: RowType[]) => void;

export interface MenuSelectHandler {
	close(): void;
	onSelect(callback: MenuSelectCallback): this;
	onClose(callback: () => void): this;
	onWillClose(callback: () => void): this;
}

export const PopMenu = {
	show(
		data: RowType[],
		{
			refer,
			columnOption = {},
			useAction = false,
			popupPosition = 'bottom-left',
			noIndicator = false,
			focus = true,
			width = 'auto',
			minWidth,
			maxWidth,
			path,
			extra,
		}: PopMenuOptions = {},
	): MenuSelectHandler {
		const type = columnOption.type ?? 'type';
		const children = columnOption.children ?? 'children';
		const checked = columnOption.checked ?? 'checked';
		const icon = columnOption.icon ?? 'icon';
		const disabled = columnOption.disabled ?? 'disabled';
		const text = columnOption.text ?? 'text';
		const onClick = columnOption.onClick ?? 'onClick';

		let onClose: (() => void) | undefined;
		let onWillClose: (() => void) | undefined;
		let onSelect: MenuSelectCallback | undefined;
		let subMenuTimeout: number | undefined;
		const container = (
			<div
				class={popMenuStyle}
				tabIndex={0}
				onKeyDown={(evt) => {
					// console.log(evt.key);
					if (evt.key === 'ArrowDown') {
						evt.preventDefault();
						evt.stopPropagation();
						const items = Array.from(container.querySelectorAll<HTMLDivElement>(':scope>div.item'));
						const actived = items.findIndex((item) => item === document.activeElement);
						if (actived >= 0) {
							if (actived < items.length - 1) {
								items[actived + 1].focus();
							}
						} else {
							items[0].focus();
						}
					} else if (evt.key === 'ArrowUp') {
						evt.preventDefault();
						evt.stopPropagation();
						const items = Array.from(container.querySelectorAll<HTMLDivElement>(':scope>div.item'));
						const actived = items.findIndex((item) => item === document.activeElement);
						if (actived >= 0) {
							if (actived > 0) {
								items[actived - 1].focus();
							}
						} else {
							items[items.length - 1].focus();
						}
					} else if (evt.key === 'Enter') {
						evt.preventDefault();
						evt.stopPropagation();
					}
				}}
			>
				{data.map((row) => {
					if (row[type] === 'line') {
						return <div class="line" />;
					} else if (row[type] === 'caption') {
						return <div class="caption">{row[text] + ''}</div>;
					} else {
						const iconSpan = (<span class="icon" />) as HTMLSpanElement;
						const iconStr = row[checked] ? SVGCheck : row[icon];
						const onClickFunc = row[onClick];
						if (typeof iconStr === 'string') {
							iconSpan.innerHTML = iconStr;
						}
						const arrowSpan = (<span class="arrow" />) as HTMLSpanElement;
						const hasChildren = Array.isArray(row[children]) && row[children].length > 0;
						if (hasChildren) {
							arrowSpan.innerHTML = SVGChevronRight;
						}
						const isDisabled = row[disabled];
						return (
							// biome-ignore lint/a11y/useKeyWithClickEvents: <>
							<div
								class={['item', isDisabled ? 'disabled' : '']}
								tabIndex={0}
								onPointerEnter={function () {
									this.focus();
								}}
								onFocus={function () {
									if (typeof subMenuTimeout === 'number') clearTimeout(subMenuTimeout);
									container.querySelectorAll(':scope>div.item').forEach((item) => {
										if (item !== this) {
											item.classList.remove('active');
										}
									});
									if (hasChildren && !pop.isAction) {
										openSubMenu(this, row);
									}
								}}
								onClick={function () {
									if (isDisabled) return;
									if (hasChildren) {
										if (pop.isAction) {
											openSubMenu(this, row, 0);
										}
										return;
									}
									pop.close();
									if (typeof onClickFunc === 'function') {
										onClickFunc(row, extra);
									}
									onSelect?.(row, [...(path ?? []), row]);
								}}
							>
								{iconSpan}
								<span class="text">{row[text] + ''}</span>
								{arrowSpan}
							</div>
						);
					}
				})}
			</div>
		) as HTMLDivElement;
		const openSubMenu = (lineDiv: HTMLDivElement, row: RowType, delay = 500) => {
			subMenuTimeout = setTimeout(() => {
				lineDiv.classList.add('active');
				const subMenu = PopMenu.show(row[children] as RowType[], {
					columnOption,
					refer: lineDiv,
					popupPosition: 'right-top',
					useAction,
					noIndicator: true,
					path: [...(path ?? []), row],
				});
				subMenu.onClose(() => {
					lineDiv.classList.remove('active');
				});
				subMenu.onSelect((subRow, path) => {
					subMenu.close();
					pop.close();
					onSelect?.(subRow, path);
				});
			}, delay);
		};
		const pop = Selector.show(container, {
			refer,
			popupPosition,
			focus,
			useAction,
			width,
			minWidth,
			maxWidth,
			extraClass: 'no-h-padding no-v-padding',
			noActionBar: true,
			noIndicator,
		})
			.onOpen(() => {
				//l.css('maxHeight', l.getLineHeight() * maxShowLines + 'px').refresh();
				setTimeout(() => {
					container.focus();
				});
			})
			.onWillClose(() => {
				onWillClose?.();
			})
			.onClose(() => {
				onClose?.();
			});
		return {
			close() {
				pop.close();
			},
			onSelect(callback) {
				onSelect = callback;
				return this;
			},
			onClose(callback) {
				onClose = callback;
				return this;
			},
			onWillClose(callback) {
				onWillClose = callback;
				return this;
			},
		};
	},
};
